#pragma once
#include "XyNet/Service/RpcArgument.h"
#include "XyNet/Service/RpcCallback.h"
#include "XyNet/Channel/RpcChannel.h"
#include "XyNet/Service/RpcController.h"
#include "XyNet/Service/RpcMethod.h"
#include "XyNet/Service/RpcService.h"
#include "Rpc.service.message.pb.h"

namespace XyNet
{

class RpcErrors
{
public:
	static shared_ptr<RpcError> createError(int code);

	static const int ExceedMaxMessagePacketSize = 0x3DFB2578;
	static const int FileTranslateError = 0xFB8771DA;
	static const int InvalidArgument = 0xBA4B0C62;
	static const int InvalidMessage = 0xA961BA1B;
	static const int LogicError = 0x257888F4;
	static const int NotConnected = 0x256B46E0;
	static const int NotError = 0x00000000;
	static const int NotHeartBeat = 0x7731BE50;
	static const int ParseMessageFailed = 0xD2005C10;
	static const int ReachMaxConnections = 0x022C37CF;
	static const int ServiceNotFound = 0x7DF21CD0;
	static const int SocketError = 0x451C5B51;
	static const int Timeout = 0x0E4CFC4E;
	static const int UnknownError = 0xFFFFFFFF;
};

class BaseService : public XyNet::RpcService
{
public:
	class SendErrorMethod : public XyNet::RpcMethod
	{
	public:
		typedef BaseServiceMessage::SendErrorRequest Request;
		typedef BaseServiceMessage::SendErrorResponse Response;

		typedef XyNet::RpcController Controller;

		class Argument : public XyNet::RpcArgument
		{
		public:
			Argument();

			shared_ptr<Controller> getController();
			shared_ptr<const Request> getRequest() const;
			shared_ptr<Response> getResponse();

		private:
			virtual shared_ptr<XyNet::RpcArgument> clone() override;
			virtual void initializeController(XyNet::RpcSocketChannel* socketChannel) override;
		};

		class Callback : public XyNet::RpcCallback
		{
		public:
			Callback(shared_ptr<XyNet::RpcArgument> argument,
				const function<void(Argument*)>& responseHandler,
				const function<void(Argument*)>& exceptionHandler);

		private:
			virtual shared_ptr<XyNet::RpcCallback> clone() override;
			virtual void doResponseHandler() override;
			virtual void doExceptionHandler() override;

		private:
			function<void(Argument*)> _responseHandler;
			function<void(Argument*)> _exceptionHandler;
		};

		SendErrorMethod(shared_ptr<XyNet::RpcChannel> channel);

		shared_ptr<Request> getRequest();
		void call(
			const function<void(Argument*)>& responseHandler =
			function<void(Argument*)>(),
			const function<void(Argument*)>& exceptionHandler =
			function<void(Argument*)>());

	private:
		shared_ptr<XyNet::RpcChannel> _channel;
		shared_ptr<Argument> _argument;
	};

	virtual void onSendError(SendErrorMethod::Argument* argument) = 0;

	class SendHeartBeatMethod : public XyNet::RpcMethod
	{
	public:
		typedef BaseServiceMessage::SendHeartBeatRequest Request;
		typedef BaseServiceMessage::SendHeartBeatResponse Response;

		typedef XyNet::RpcController Controller;

		class Argument : public XyNet::RpcArgument
		{
		public:
			Argument();

			shared_ptr<Controller> getController();
			shared_ptr<const Request> getRequest() const;
			shared_ptr<Response> getResponse();

		private:
			virtual shared_ptr<XyNet::RpcArgument> clone() override;
			virtual void initializeController(XyNet::RpcSocketChannel* socketChannel) override;
		};

		class Callback : public XyNet::RpcCallback
		{
		public:
			Callback(shared_ptr<XyNet::RpcArgument> argument,
				const function<void(Argument*)>& responseHandler,
				const function<void(Argument*)>& exceptionHandler);

		private:
			virtual shared_ptr<XyNet::RpcCallback> clone() override;
			virtual void doResponseHandler() override;
			virtual void doExceptionHandler() override;

		private:
			function<void(Argument*)> _responseHandler;
			function<void(Argument*)> _exceptionHandler;
		};

		SendHeartBeatMethod(shared_ptr<XyNet::RpcChannel> channel);

		shared_ptr<Request> getRequest();
		void call(
			const function<void(Argument*)>& responseHandler =
			function<void(Argument*)>(),
			const function<void(Argument*)>& exceptionHandler =
			function<void(Argument*)>());

	private:
		shared_ptr<XyNet::RpcChannel> _channel;
		shared_ptr<Argument> _argument;
	};

	virtual void onSendHeartBeat(SendHeartBeatMethod::Argument* argument) = 0;

	class GetUtcTimeMethod : public XyNet::RpcMethod
	{
	public:
		typedef BaseServiceMessage::GetUtcTimeRequest Request;
		typedef BaseServiceMessage::GetUtcTimeResponse Response;

		typedef XyNet::RpcController Controller;

		class Argument : public XyNet::RpcArgument
		{
		public:
			Argument();

			shared_ptr<Controller> getController();
			shared_ptr<const Request> getRequest() const;
			shared_ptr<Response> getResponse();

		private:
			virtual shared_ptr<XyNet::RpcArgument> clone() override;
			virtual void initializeController(XyNet::RpcSocketChannel* socketChannel) override;
		};

		class Callback : public XyNet::RpcCallback
		{
		public:
			Callback(shared_ptr<XyNet::RpcArgument> argument,
				const function<void(Argument*)>& responseHandler,
				const function<void(Argument*)>& exceptionHandler);

		private:
			virtual shared_ptr<XyNet::RpcCallback> clone() override;
			virtual void doResponseHandler() override;
			virtual void doExceptionHandler() override;

		private:
			function<void(Argument*)> _responseHandler;
			function<void(Argument*)> _exceptionHandler;
		};

		GetUtcTimeMethod(shared_ptr<XyNet::RpcChannel> channel);

		shared_ptr<Request> getRequest();
		void call(
			const function<void(Argument*)>& responseHandler =
			function<void(Argument*)>(),
			const function<void(Argument*)>& exceptionHandler =
			function<void(Argument*)>());

	private:
		shared_ptr<XyNet::RpcChannel> _channel;
		shared_ptr<Argument> _argument;
	};

	virtual void onGetUtcTime(GetUtcTimeMethod::Argument* argument) = 0;

	class GetBrokerQueriesMethod : public XyNet::RpcMethod
	{
	public:
		typedef BaseServiceMessage::GetBrokerQueriesRequest Request;
		typedef BaseServiceMessage::GetBrokerQueriesResponse Response;

		typedef XyNet::RpcController Controller;

		class Argument : public XyNet::RpcArgument
		{
		public:
			Argument();

			shared_ptr<Controller> getController();
			shared_ptr<const Request> getRequest() const;
			shared_ptr<Response> getResponse();

		private:
			virtual shared_ptr<XyNet::RpcArgument> clone() override;
			virtual void initializeController(XyNet::RpcSocketChannel* socketChannel) override;
		};

		class Callback : public XyNet::RpcCallback
		{
		public:
			Callback(shared_ptr<XyNet::RpcArgument> argument,
				const function<void(Argument*)>& responseHandler,
				const function<void(Argument*)>& exceptionHandler);

		private:
			virtual shared_ptr<XyNet::RpcCallback> clone() override;
			virtual void doResponseHandler() override;
			virtual void doExceptionHandler() override;

		private:
			function<void(Argument*)> _responseHandler;
			function<void(Argument*)> _exceptionHandler;
		};

		GetBrokerQueriesMethod(shared_ptr<XyNet::RpcChannel> channel);

		shared_ptr<Request> getRequest();
		void call(
			const function<void(Argument*)>& responseHandler =
			function<void(Argument*)>(),
			const function<void(Argument*)>& exceptionHandler =
			function<void(Argument*)>());

	private:
		shared_ptr<XyNet::RpcChannel> _channel;
		shared_ptr<Argument> _argument;
	};

	virtual void onGetBrokerQueries(GetBrokerQueriesMethod::Argument* argument) = 0;

	BaseService();

	virtual shared_ptr<XyNet::RpcArgument> createMethodArgument(int methodId) const override;
	virtual void onMethod(int methodId, XyNet::RpcArgument* argument) override;
};

class DownloadService : public XyNet::RpcService
{
public:
	class GetResourceInfoMethod : public XyNet::RpcMethod
	{
	public:
		typedef DownloadServiceMessage::GetResourceInfoRequest Request;
		typedef DownloadServiceMessage::GetResourceInfoResponse Response;

		typedef XyNet::RpcController Controller;

		class Argument : public XyNet::RpcArgument
		{
		public:
			Argument();

			shared_ptr<Controller> getController();
			shared_ptr<const Request> getRequest() const;
			shared_ptr<Response> getResponse();

		private:
			virtual shared_ptr<XyNet::RpcArgument> clone() override;
			virtual void initializeController(XyNet::RpcSocketChannel* socketChannel) override;
		};

		class Callback : public XyNet::RpcCallback
		{
		public:
			Callback(shared_ptr<XyNet::RpcArgument> argument,
				const function<void(Argument*)>& responseHandler,
				const function<void(Argument*)>& exceptionHandler);

		private:
			virtual shared_ptr<XyNet::RpcCallback> clone() override;
			virtual void doResponseHandler() override;
			virtual void doExceptionHandler() override;

		private:
			function<void(Argument*)> _responseHandler;
			function<void(Argument*)> _exceptionHandler;
		};

		GetResourceInfoMethod(shared_ptr<XyNet::RpcChannel> channel);

		shared_ptr<Request> getRequest();
		void call(
			const function<void(Argument*)>& responseHandler =
			function<void(Argument*)>(),
			const function<void(Argument*)>& exceptionHandler =
			function<void(Argument*)>());

	private:
		shared_ptr<XyNet::RpcChannel> _channel;
		shared_ptr<Argument> _argument;
	};

	virtual void onGetResourceInfo(GetResourceInfoMethod::Argument* argument) = 0;

	class GetFileDataMethod : public XyNet::RpcMethod
	{
	public:
		typedef DownloadServiceMessage::GetFileDataRequest Request;
		typedef DownloadServiceMessage::GetFileDataResponse Response;

		typedef XyNet::RpcController Controller;

		class Argument : public XyNet::RpcArgument
		{
		public:
			Argument();

			shared_ptr<Controller> getController();
			shared_ptr<const Request> getRequest() const;
			shared_ptr<Response> getResponse();

		private:
			virtual shared_ptr<XyNet::RpcArgument> clone() override;
			virtual void initializeController(XyNet::RpcSocketChannel* socketChannel) override;
		};

		class Callback : public XyNet::RpcCallback
		{
		public:
			Callback(shared_ptr<XyNet::RpcArgument> argument,
				const function<void(Argument*)>& responseHandler,
				const function<void(Argument*)>& exceptionHandler);

		private:
			virtual shared_ptr<XyNet::RpcCallback> clone() override;
			virtual void doResponseHandler() override;
			virtual void doExceptionHandler() override;

		private:
			function<void(Argument*)> _responseHandler;
			function<void(Argument*)> _exceptionHandler;
		};

		GetFileDataMethod(shared_ptr<XyNet::RpcChannel> channel);

		shared_ptr<Request> getRequest();
		void call(
			const function<void(Argument*)>& responseHandler =
			function<void(Argument*)>(),
			const function<void(Argument*)>& exceptionHandler =
			function<void(Argument*)>());

	private:
		shared_ptr<XyNet::RpcChannel> _channel;
		shared_ptr<Argument> _argument;
	};

	virtual void onGetFileData(GetFileDataMethod::Argument* argument) = 0;

	DownloadService();

	virtual shared_ptr<XyNet::RpcArgument> createMethodArgument(int methodId) const override;
	virtual void onMethod(int methodId, XyNet::RpcArgument* argument) override;
};

class UploadService : public XyNet::RpcService
{
public:
	class CreateUploadTaskMethod : public XyNet::RpcMethod
	{
	public:
		typedef UploadServiceMessage::CreateUploadTaskRequest Request;
		typedef UploadServiceMessage::CreateUploadTaskResponse Response;

		typedef XyNet::RpcController Controller;

		class Argument : public XyNet::RpcArgument
		{
		public:
			Argument();

			shared_ptr<Controller> getController();
			shared_ptr<const Request> getRequest() const;
			shared_ptr<Response> getResponse();

		private:
			virtual shared_ptr<XyNet::RpcArgument> clone() override;
			virtual void initializeController(XyNet::RpcSocketChannel* socketChannel) override;
		};

		class Callback : public XyNet::RpcCallback
		{
		public:
			Callback(shared_ptr<XyNet::RpcArgument> argument,
				const function<void(Argument*)>& responseHandler,
				const function<void(Argument*)>& exceptionHandler);

		private:
			virtual shared_ptr<XyNet::RpcCallback> clone() override;
			virtual void doResponseHandler() override;
			virtual void doExceptionHandler() override;

		private:
			function<void(Argument*)> _responseHandler;
			function<void(Argument*)> _exceptionHandler;
		};

		CreateUploadTaskMethod(shared_ptr<XyNet::RpcChannel> channel);

		shared_ptr<Request> getRequest();
		void call(
			const function<void(Argument*)>& responseHandler =
			function<void(Argument*)>(),
			const function<void(Argument*)>& exceptionHandler =
			function<void(Argument*)>());

	private:
		shared_ptr<XyNet::RpcChannel> _channel;
		shared_ptr<Argument> _argument;
	};

	virtual void onCreateUploadTask(CreateUploadTaskMethod::Argument* argument) = 0;

	class GetUploadInfoMethod : public XyNet::RpcMethod
	{
	public:
		typedef UploadServiceMessage::GetUploadInfoRequest Request;
		typedef UploadServiceMessage::GetUploadInfoResponse Response;

		typedef XyNet::RpcController Controller;

		class Argument : public XyNet::RpcArgument
		{
		public:
			Argument();

			shared_ptr<Controller> getController();
			shared_ptr<const Request> getRequest() const;
			shared_ptr<Response> getResponse();

		private:
			virtual shared_ptr<XyNet::RpcArgument> clone() override;
			virtual void initializeController(XyNet::RpcSocketChannel* socketChannel) override;
		};

		class Callback : public XyNet::RpcCallback
		{
		public:
			Callback(shared_ptr<XyNet::RpcArgument> argument,
				const function<void(Argument*)>& responseHandler,
				const function<void(Argument*)>& exceptionHandler);

		private:
			virtual shared_ptr<XyNet::RpcCallback> clone() override;
			virtual void doResponseHandler() override;
			virtual void doExceptionHandler() override;

		private:
			function<void(Argument*)> _responseHandler;
			function<void(Argument*)> _exceptionHandler;
		};

		GetUploadInfoMethod(shared_ptr<XyNet::RpcChannel> channel);

		shared_ptr<Request> getRequest();
		void call(
			const function<void(Argument*)>& responseHandler =
			function<void(Argument*)>(),
			const function<void(Argument*)>& exceptionHandler =
			function<void(Argument*)>());

	private:
		shared_ptr<XyNet::RpcChannel> _channel;
		shared_ptr<Argument> _argument;
	};

	virtual void onGetUploadInfo(GetUploadInfoMethod::Argument* argument) = 0;

	UploadService();

	virtual shared_ptr<XyNet::RpcArgument> createMethodArgument(int methodId) const override;
	virtual void onMethod(int methodId, XyNet::RpcArgument* argument) override;
};

}
